import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext, colorchooser, simpledialog
import os
import hashlib
import base64
import re

class EnhancedNotepad:
    def __init__(self, root):
        # 初始化主窗口
        self.root = root
        self.root.title("增强版记事本")
        self.root.geometry("900x700")
        
        # 当前文件路径，None表示未保存的新文件
        self.current_file = None
        
        # 剪贴板历史
        self.clipboard_history = []
        self.max_clipboard_history = 5
        
        # 用于格式化的tag名称计数器
        self.tag_counter = 0
        
        # 创建菜单栏
        self.create_menu()
        
        # 创建工具栏
        self.create_toolbar()
        
        # 创建查找替换框架
        self.find_frame = tk.Frame(self.root)
        
        # 创建文本区域
        self.text_area = scrolledtext.ScrolledText(
            root, 
            wrap=tk.WORD,
            font=("Arial", 12),
            undo=True,
            maxundo=100
        )
        self.text_area.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 状态栏
        self.status_bar = tk.Label(root, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        
        # 绑定快捷键
        self.bind_shortcuts()
        
        # 跟踪文本修改状态
        self.text_modified = False
        self.text_area.bind("<<Modified>>", self.on_text_modified)
        
        # 更新状态栏
        self.update_status("就绪")

    def create_menu(self):
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)

        # 文件菜单
        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="文件", menu=file_menu)
        file_menu.add_command(label="新建", command=self.new_file, accelerator="Ctrl+N")
        file_menu.add_command(label="打开", command=self.open_file, accelerator="Ctrl+O")
        file_menu.add_command(label="保存", command=self.save_file, accelerator="Ctrl+S")
        file_menu.add_command(label="另存为", command=self.save_as_file)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.exit_app)

        # 编辑菜单
        edit_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="编辑", menu=edit_menu)
        edit_menu.add_command(label="撤销", command=self.undo, accelerator="Ctrl+Z")
        edit_menu.add_command(label="重做", command=self.redo, accelerator="Ctrl+Y")
        edit_menu.add_separator()
        edit_menu.add_command(label="剪切", command=self.cut, accelerator="Ctrl+X")
        edit_menu.add_command(label="复制", command=self.copy, accelerator="Ctrl+C")
        edit_menu.add_command(label="粘贴", command=self.paste, accelerator="Ctrl+V")
        edit_menu.add_command(label="粘贴历史", command=self.show_clipboard_history)
        edit_menu.add_separator()
        edit_menu.add_command(label="全选", command=self.select_all, accelerator="Ctrl+A")
        edit_menu.add_command(label="查找", command=self.show_find, accelerator="Ctrl+F")
        edit_menu.add_command(label="替换", command=self.show_replace, accelerator="Ctrl+H")

        # 格式菜单
        format_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="格式", menu=format_menu)
        format_menu.add_command(label="字体", command=self.choose_font)
        format_menu.add_command(label="颜色", command=self.choose_color)
        format_menu.add_separator()
        format_menu.add_command(label="粗体", command=self.toggle_bold, accelerator="Ctrl+B")
        format_menu.add_command(label="斜体", command=self.toggle_italic, accelerator="Ctrl+I")
        format_menu.add_command(label="下划线", command=self.toggle_underline, accelerator="Ctrl+U")
        format_menu.add_command(label="删除线", command=self.toggle_strikethrough)

    def create_toolbar(self):
        toolbar = tk.Frame(self.root, bd=1, relief=tk.RAISED)
        toolbar.pack(side=tk.TOP, fill=tk.X)

        # 撤销按钮
        undo_btn = tk.Button(toolbar, text="撤销", command=self.undo)
        undo_btn.pack(side=tk.LEFT, padx=2, pady=2)

        # 重做按钮
        redo_btn = tk.Button(toolbar, text="重做", command=self.redo)
        redo_btn.pack(side=tk.LEFT, padx=2, pady=2)

        # 分隔线
        sep1 = tk.Frame(toolbar, width=2, height=20, bg='gray')
        sep1.pack(side=tk.LEFT, padx=2, pady=2)

        # 剪切按钮
        cut_btn = tk.Button(toolbar, text="剪切", command=self.cut)
        cut_btn.pack(side=tk.LEFT, padx=2, pady=2)

        # 复制按钮
        copy_btn = tk.Button(toolbar, text="复制", command=self.copy)
        copy_btn.pack(side=tk.LEFT, padx=2, pady=2)

        # 粘贴按钮
        paste_btn = tk.Button(toolbar, text="粘贴", command=self.paste)
        paste_btn.pack(side=tk.LEFT, padx=2, pady=2)

        # 分隔线
        sep2 = tk.Frame(toolbar, width=2, height=20, bg='gray')
        sep2.pack(side=tk.LEFT, padx=2, pady=2)

        # 粗体按钮
        bold_btn = tk.Button(toolbar, text="粗体", command=self.toggle_bold)
        bold_btn.pack(side=tk.LEFT, padx=2, pady=2)

        # 斜体按钮
        italic_btn = tk.Button(toolbar, text="斜体", command=self.toggle_italic)
        italic_btn.pack(side=tk.LEFT, padx=2, pady=2)

        # 下划线按钮
        underline_btn = tk.Button(toolbar, text="下划线", command=self.toggle_underline)
        underline_btn.pack(side=tk.LEFT, padx=2, pady=2)

        # 查找按钮
        find_btn = tk.Button(toolbar, text="查找", command=self.show_find)
        find_btn.pack(side=tk.LEFT, padx=2, pady=2)

    def bind_shortcuts(self):
        self.root.bind("<Control-n>", lambda event: self.new_file())
        self.root.bind("<Control-o>", lambda event: self.open_file())
        self.root.bind("<Control-s>", lambda event: self.save_file())
        self.root.bind("<Control-z>", lambda event: self.undo())
        self.root.bind("<Control-y>", lambda event: self.redo())
        self.root.bind("<Control-x>", lambda event: self.cut())
        self.root.bind("<Control-c>", lambda event: self.copy())
        self.root.bind("<Control-v>", lambda event: self.paste())
        self.root.bind("<Control-a>", lambda event: self.select_all())
        self.root.bind("<Control-f>", lambda event: self.show_find())
        self.root.bind("<Control-h>", lambda event: self.show_replace())
        self.root.bind("<Control-b>", lambda event: self.toggle_bold())
        self.root.bind("<Control-i>", lambda event: self.toggle_italic())
        self.root.bind("<Control-u>", lambda event: self.toggle_underline())

    def update_status(self, message):
        self.status_bar.config(text=message)

    def on_text_modified(self, event):
        if self.text_area.edit_modified():
            self.text_modified = True
            title = self.root.title()
            if not title.startswith("*"):
                self.root.title("*" + title)
        self.text_area.edit_modified(False)

    def new_file(self):
        if self.check_save():
            self.text_area.delete(1.0, tk.END)
            self.current_file = None
            self.root.title("新建文件 - 增强版记事本")
            self.text_modified = False
            self.update_status("新建文件")

    def open_file(self):
        if self.check_save():
            file_path = filedialog.askopenfilename(
                defaultextension=".txt",
                filetypes=[("HTML文件", "*.html"), ("文本文件", "*.txt"), ("所有文件", "*.*")]
            )
            if file_path:
                try:
                    # 尝试读取并解密
                    content = self.decrypt_file(file_path)
                    if content is None:
                        # 如果无法解密，可能是普通文本
                        with open(file_path, 'r', encoding='utf-8') as f:
                            content = f.read()
                        
                        # 检查是否是HTML格式
                        if file_path.lower().endswith('.html') and '<html>' in content.lower():
                            self.load_html_content(content)
                        else:
                            self.current_file = file_path
                            self.root.title(f"{os.path.basename(file_path)} - 增强版记事本")
                            self.text_area.delete(1.0, tk.END)
                            self.text_area.insert(1.0, content)
                        
                        self.text_modified = False
                        self.update_status(f"已打开: {os.path.basename(file_path)}")
                    else:
                        # 解密成功
                        self.current_file = file_path
                        self.root.title(f"{os.path.basename(file_path)} - 增强版记事本")
                        self.load_html_content(content)
                        self.text_modified = False
                        self.update_status(f"已解密并打开: {os.path.basename(file_path)}")
                except Exception as e:
                    messagebox.showerror("错误", f"无法打开文件: {str(e)}")

    def save_file(self):
        if self.current_file:
            # 自动加密保存
            self.encrypt_and_save(self.current_file)
        else:
            self.save_as_file()

    def save_as_file(self):
        file_path = filedialog.asksaveasfilename(
            defaultextension=".html",
            filetypes=[("HTML文件", "*.html"), ("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        if file_path:
            # 提示是否加密
            encrypt_choice = messagebox.askyesno("加密保存", "是否加密保存此文件？")
            if encrypt_choice:
                # 加密保存
                self.encrypt_and_save(file_path)
            else:
                # 明文保存
                if file_path.lower().endswith('.html'):
                    content = self.get_html_content()
                else:
                    content = self.text_area.get(1.0, tk.END)
                
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(content)
                
                self.current_file = file_path
                self.root.title(f"{os.path.basename(file_path)} - 增强版记事本")
                self.text_modified = False
                self.update_status(f"已保存: {os.path.basename(file_path)}")

    def get_html_content(self):
        """将文本区域内容转换为HTML格式"""
        content = self.text_area.get(1.0, tk.END)
        lines = content.split('\n')
        
        html_lines = ['<html><body>']
        
        for line in lines:
            if line.strip():
                # 转义HTML特殊字符
                line = line.replace('&', '&amp;').replace('<', '<').replace('>', '>')
                
                # 获取当前行的格式化信息
                formatted_line = self.format_line_to_html(line)
                html_lines.append(formatted_line)
            else:
                html_lines.append('<br>')
        
        html_lines.append('</body></html>')
        return '\n'.join(html_lines)

    def format_line_to_html(self, line):
        """将一行文本转换为带格式的HTML"""
        # 这里需要根据实际的tag信息来生成HTML
        # 简化版本：直接返回文本
        return f'<p>{line}</p>'

    def load_html_content(self, html_content):
        """从HTML内容加载到文本区域"""
        # 简化版本：只提取纯文本
        from html.parser import HTMLParser
        
        class HTMLTextExtractor(HTMLParser):
            def __init__(self):
                super().__init__()
                self.text_parts = []
            
            def handle_data(self, data):
                self.text_parts.append(data)
        
        parser = HTMLTextExtractor()
        parser.feed(html_content)
        
        text = ''.join(parser.text_parts)
        self.text_area.delete(1.0, tk.END)
        self.text_area.insert(1.0, text)

    def encrypt_and_save(self, file_path):
        max_attempts = 3  # 最多尝试3次
    
        for attempt in range(max_attempts):
            # 第一次输入密码
            password1 = simpledialog.askstring("设置密码", f"请输入密码（用于加密）(尝试 {attempt+1}/{max_attempts}）:", show='*')
            if not password1:
                return  # 用户取消
            
            # 检查密码强度
            if len(password1) < 4:
                if not messagebox.askyesno("密码太短", "密码少于4位，安全性较低，确定继续？"):
                    continue  # 让用户重新输入
        
            # 确认密码
            password2 = simpledialog.askstring("确认密码", "请再次输入密码以确认:", show='*')
            if not password2:
                return  # 用户取消
            
            # 比较两次输入
            if password1 == password2:
                break  # 密码匹配，跳出循环
            else:
                messagebox.showerror("密码不匹配", f"两次输入的密码不一致，请重新输入！")
                if attempt < max_attempts - 1:
                    continue
                else:
                    messagebox.showerror("操作取消", "密码输入错误次数过多，已取消加密保存")
                    return
        else:
            return  # 达到最大尝试次数
    
        # 密码设置成功，继续加密保存
        key = self.derive_key(password1)
        
        # 根据文件扩展名决定保存格式
        if file_path.lower().endswith('.html'):
            content = self.get_html_content()
        else:
            content = self.text_area.get(1.0, tk.END)
            
        encrypted_content = self.encrypt_string(content, key)
    
        try:
            with open(file_path, 'wb') as f:
                f.write(encrypted_content)
        
            self.current_file = file_path
            self.root.title(f"{os.path.basename(file_path)} - 增强版记事本")
            self.text_modified = False
            self.update_status(f"已加密保存: {os.path.basename(file_path)}")
        
            messagebox.showinfo("成功", "文件已成功加密保存！")
        
        except Exception as e:
            messagebox.showerror("保存失败", f"无法保存文件: {str(e)}")

    def decrypt_file(self, file_path):
        """尝试解密文件（增强版：添加多次尝试机制）"""
        max_attempts = 3
    
        for attempt in range(max_attempts):
            password = simpledialog.askstring("密码验证", f"请输入密码解密文件 (尝试 {attempt+1}/{max_attempts}):", show='*')
            if not password:
                return None  # 用户取消
            
            key = self.derive_key(password)
            try:
                with open(file_path, 'rb') as f:
                    encrypted_data = f.read()
                decrypted_content = self.decrypt_string(encrypted_data, key)
                return decrypted_content
            except Exception as e:
                if attempt < max_attempts - 1:
                    messagebox.showwarning("解密失败", f"密码错误，请重试！剩余 {max_attempts-attempt-1} 次机会")
                else:
                    messagebox.showerror("解密失败", "密码错误次数过多，解密失败")
                    return None
    
        return None

    def derive_key(self, password):
        """从密码生成密钥（SHA-256）"""
        return hashlib.sha256(password.encode('utf-8')).digest()

    def encrypt_string(self, plaintext, key):
        """使用XOR加密字符串"""
        # 将明文转为字节
        plaintext_bytes = plaintext.encode('utf-8')
        # XOR加密
        encrypted_bytes = bytes(b ^ key[i % len(key)] for i, b in enumerate(plaintext_bytes))
        # Base64编码以便存储
        return base64.b64encode(encrypted_bytes)

    def decrypt_string(self, encrypted_data, key):
        """解密字符串"""
        # Base64解码
        encrypted_bytes = base64.b64decode(encrypted_data)
        # XOR解密
        decrypted_bytes = bytes(b ^ key[i % len(key)] for i, b in enumerate(encrypted_bytes))
        # 转回字符串
        return decrypted_bytes.decode('utf-8')

    def check_save(self):
        if self.text_modified:
            result = messagebox.askyesnocancel("保存更改", "是否保存当前更改?")
            if result is None:
                return False
            elif result:
                self.save_file()
        return True

    def exit_app(self):
        if self.check_save():
            self.root.quit()

    # 编辑功能实现
    def undo(self):
        try:
            self.text_area.edit_undo()
            self.update_status("撤销操作")
        except tk.TclError:
            self.update_status("无法撤销")

    def redo(self):
        try:
            self.text_area.edit_redo()
            self.update_status("重做操作")
        except tk.TclError:
            self.update_status("无法重做")

    def cut(self):
        if self.text_area.tag_ranges(tk.SEL):
            selected_text = self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
            self.add_to_clipboard_history(selected_text)
            self.text_area.event_generate("<<Cut>>")
            self.update_status("已剪切选中文本")
        else:
            self.update_status("未选中文本")

    def copy(self):
        if self.text_area.tag_ranges(tk.SEL):
            selected_text = self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
            self.add_to_clipboard_history(selected_text)
            self.text_area.event_generate("<<Copy>>")
            self.update_status("已复制选中文本")
        else:
            self.update_status("未选中文本")

    def paste(self):
        self.text_area.event_generate("<<Paste>>")
        self.update_status("已粘贴内容")

    def add_to_clipboard_history(self, text):
        if text and text not in self.clipboard_history:
            self.clipboard_history.insert(0, text)
            if len(self.clipboard_history) > self.max_clipboard_history:
                self.clipboard_history.pop()

    def show_clipboard_history(self):
        if not self.clipboard_history:
            messagebox.showinfo("剪贴板历史", "剪贴板历史为空")
            return

        history_window = tk.Toplevel(self.root)
        history_window.title("剪贴板历史")
        history_window.geometry("400x300")

        tk.Label(history_window, text="最近复制的内容:", font=("Arial", 10, "bold")).pack(pady=5)

        listbox = tk.Listbox(history_window, width=50, height=10)
        listbox.pack(pady=5, padx=10, fill=tk.BOTH, expand=True)

        for i, item in enumerate(self.clipboard_history, 1):
            display_text = item[:50] + "..." if len(item) > 50 else item
            listbox.insert(tk.END, f"{i}. {display_text}")

        def paste_selected():
            selection = listbox.curselection()
            if selection:
                selected_text = self.clipboard_history[selection[0]]
                self.text_area.insert(tk.INSERT, selected_text)
                history_window.destroy()

        btn_frame = tk.Frame(history_window)
        btn_frame.pack(pady=5)
        tk.Button(btn_frame, text="粘贴选中", command=paste_selected).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="关闭", command=history_window.destroy).pack(side=tk.LEFT, padx=5)

    def select_all(self):
        self.text_area.tag_add(tk.SEL, "1.0", tk.END)
        self.text_area.mark_set(tk.INSERT, "1.0")
        self.text_area.see(tk.INSERT)
        self.update_status("已全选文本")

    def show_find(self):
        self.show_find_replace(is_replace=False)

    def show_replace(self):
        self.show_find_replace(is_replace=True)

    def show_find_replace(self, is_replace=False):
        if hasattr(self, 'find_frame') and self.find_frame.winfo_ismapped():
            self.find_frame.pack_forget()

        self.find_frame = tk.Frame(self.root, relief=tk.SUNKEN, bd=1)
        self.find_frame.pack(side=tk.BOTTOM, fill=tk.X)

        tk.Label(self.find_frame, text="查找:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        find_entry = tk.Entry(self.find_frame, width=30)
        find_entry.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)
        find_entry.focus_set()

        if is_replace:
            tk.Label(self.find_frame, text="替换为:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
            replace_entry = tk.Entry(self.find_frame, width=30)
            replace_entry.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)

        options_frame = tk.Frame(self.find_frame)
        options_frame.grid(row=2, column=0, columnspan=2, padx=5, pady=5, sticky=tk.W)

        case_sensitive = tk.BooleanVar()
        tk.Checkbutton(options_frame, text="匹配大小写", variable=case_sensitive).pack(side=tk.LEFT, padx=5)

        btn_frame = tk.Frame(self.find_frame)
        btn_frame.grid(row=3, column=0, columnspan=2, padx=5, pady=5)

        def find_next():
            self.find_text(find_entry.get(), case_sensitive.get(), is_replace=False)

        def find_prev():
            self.find_text(find_entry.get(), case_sensitive.get(), is_replace=False, backward=True)

        def replace_one():
            if is_replace:
                self.replace_text(find_entry.get(), replace_entry.get(), case_sensitive.get(), replace_all=False)

        def replace_all():
            if is_replace:
                self.replace_text(find_entry.get(), replace_entry.get(), case_sensitive.get(), replace_all=True)

        def close_find():
            self.find_frame.pack_forget()

        tk.Button(btn_frame, text="查找下一个", command=find_next).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="查找上一个", command=find_prev).pack(side=tk.LEFT, padx=5)

        if is_replace:
            tk.Button(btn_frame, text="替换", command=replace_one).pack(side=tk.LEFT, padx=5)
            tk.Button(btn_frame, text="全部替换", command=replace_all).pack(side=tk.LEFT, padx=5)

        tk.Button(btn_frame, text="关闭", command=close_find).pack(side=tk.LEFT, padx=5)

    def find_text(self, search_text, case_sensitive, is_replace=False, backward=False):
        if not search_text:
            self.update_status("查找内容为空")
            return

        start_pos = self.text_area.index(tk.INSERT)
        content = self.text_area.get(1.0, tk.END)

        if case_sensitive:
            search_content = content
            search_term = search_text
        else:
            search_content = content.lower()
            search_term = search_text.lower()

        if backward:
            pos = search_content.rfind(search_term, 0, start_pos)
            if pos == -1:
                pos = search_content.rfind(search_term, start_pos, len(search_content))
        else:
            pos = search_content.find(search_term, start_pos)
            if pos == -1:
                pos = search_content.find(search_term, 0, start_pos)

        if pos == -1:
            self.update_status(f"未找到: {search_text}")
            messagebox.showinfo("查找", f"未找到: {search_text}")
            return

        line_start = content.count('\n', 0, pos) + 1
        col_start = pos - content.rfind('\n', 0, pos)

        self.text_area.tag_remove(tk.SEL, 1.0, tk.END)
        self.text_area.tag_add(tk.SEL, f"{line_start}.{col_start}", f"{line_start}.{col_start + len(search_text)}")
        self.text_area.mark_set(tk.INSERT, f"{line_start}.{col_start + len(search_text)}")
        self.text_area.see(tk.INSERT)
        self.update_status(f"已找到: {search_text}")

    def replace_text(self, search_text, replace_text, case_sensitive, replace_all=False):
        if not search_text:
            self.update_status("查找内容为空")
            return

        content = self.text_area.get(1.0, tk.END)

        if case_sensitive:
            search_content = content
            search_term = search_text
        else:
            search_content = content.lower()
            search_term = search_text.lower()

        count = search_content.count(search_term)

        if count == 0:
            self.update_status(f"未找到: {search_text}")
            messagebox.showinfo("替换", f"未找到: {search_text}")
            return

        if replace_all:
            if case_sensitive:
                new_content = content.replace(search_text, replace_text)
            else:
                import re
                new_content = re.compile(re.escape(search_text), re.IGNORECASE).sub(replace_text, content)
            self.text_area.delete(1.0, tk.END)
            self.text_area.insert(1.0, new_content)
            self.update_status(f"已替换 {count} 处")
            messagebox.showinfo("替换", f"已替换 {count} 处")
        else:
            if self.text_area.tag_ranges(tk.SEL):
                selected_text = self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
                if (case_sensitive and selected_text == search_text) or \
                   (not case_sensitive and selected_text.lower() == search_term):
                    self.text_area.delete(tk.SEL_FIRST, tk.SEL_LAST)
                    self.text_area.insert(tk.SEL_FIRST, replace_text)
                    self.update_status("已替换当前选中")
                    self.find_text(search_text, case_sensitive, is_replace=True)

    # 格式功能实现（修改版：只对选中的文本生效）
    def choose_font(self):
        """选择字体（只对选中文本生效）"""
        if not self.text_area.tag_ranges(tk.SEL):
            messagebox.showinfo("提示", "请先选择要修改字体的文本")
            return
            
        font_window = tk.Toplevel(self.root)
        font_window.title("选择字体")
        font_window.geometry("300x200")

        tk.Label(font_window, text="字体:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)

        fonts = list(tk.font.families())
        fonts.sort()

        font_var = tk.StringVar()
        font_listbox = tk.Listbox(font_window, listvariable=tk.StringVar(value=fonts), height=6)
        font_listbox.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W+tk.E)

        scrollbar = tk.Scrollbar(font_window, orient=tk.VERTICAL, command=font_listbox.yview)
        scrollbar.grid(row=0, column=2, sticky=tk.N+tk.S)
        font_listbox.config(yscrollcommand=scrollbar.set)

        tk.Label(font_window, text="大小:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        size_var = tk.StringVar(value="12")
        size_spinbox = tk.Spinbox(font_window, from_=8, to=72, textvariable=size_var, width=5)
        size_spinbox.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)

        def apply_font():
            if not font_listbox.curselection():
                messagebox.showwarning("警告", "请选择字体")
                return
                
            selected_font = font_listbox.get(font_listbox.curselection())
            size = size_var.get()
            
            # 为选中的文本创建新的tag
            tag_name = f"font_{self.tag_counter}"
            self.tag_counter += 1
            
            # 配置tag的字体
            self.text_area.tag_configure(
                tag_name, 
                font=(selected_font, int(size))
            )
            
            # 将tag应用到选中的文本
            self.text_area.tag_add(tag_name, tk.SEL_FIRST, tk.SEL_LAST)
            
            font_window.destroy()
            self.update_status(f"已为选中文本设置字体: {selected_font} {size}pt")

        tk.Button(font_window, text="应用", command=apply_font).grid(row=2, column=1, padx=5, pady=5, sticky=tk.E)
        tk.Button(font_window, text="取消", command=font_window.destroy).grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)

    def choose_color(self):
        """选择颜色（只对选中文本生效）"""
        if not self.text_area.tag_ranges(tk.SEL):
            messagebox.showinfo("提示", "请先选择要修改颜色的文本")
            return
            
        color = colorchooser.askcolor(title="选择文本颜色")
        if color[1]:  # 用户选择了颜色
            # 为选中的文本创建新的tag
            tag_name = f"color_{self.tag_counter}"
            self.tag_counter += 1
            
            # 配置tag的颜色
            self.text_area.tag_configure(
                tag_name, 
                foreground=color[1]
            )
            
            # 将tag应用到选中的文本
            self.text_area.tag_add(tag_name, tk.SEL_FIRST, tk.SEL_LAST)
            
            self.update_status(f"已为选中文本设置颜色: {color[1]}")

    def toggle_bold(self):
        """切换粗体（只对选中文本生效）"""
        if not self.text_area.tag_ranges(tk.SEL):
            messagebox.showinfo("提示", "请先选择要设置粗体的文本")
            return
            
        # 为选中的文本创建新的tag
        tag_name = f"bold_{self.tag_counter}"
        self.tag_counter += 1
        
        # 获取当前字体
        current_font = self.text_area.cget("font")
        font_family = current_font.split()[0] if ' ' in current_font else current_font
        font_size = current_font.split()[1] if len(current_font.split()) > 1 else "12"
        
        # 检查是否已经有粗体
        tags = self.text_area.tag_names(tk.SEL_FIRST)
        is_bold = any('bold' in self.text_area.tag_cget(tag, 'font') for tag in tags if self.text_area.tag_cget(tag, 'font'))
        
        if is_bold:
            # 取消粗体
            self.text_area.tag_configure(
                tag_name,
                font=(font_family, int(font_size))
            )
            status_msg = "已取消选中文本的粗体"
        else:
            # 应用粗体
            self.text_area.tag_configure(
                tag_name,
                font=(font_family, int(font_size), "bold")
            )
            status_msg = "已为选中文本应用粗体"
        
        # 将tag应用到选中的文本
        self.text_area.tag_add(tag_name, tk.SEL_FIRST, tk.SEL_LAST)
        self.update_status(status_msg)

    def toggle_italic(self):
        """切换斜体（只对选中文本生效）"""
        if not self.text_area.tag_ranges(tk.SEL):
            messagebox.showinfo("提示", "请先选择要设置斜体的文本")
            return
            
        # 为选中的文本创建新的tag
        tag_name = f"italic_{self.tag_counter}"
        self.tag_counter += 1
        
        # 获取当前字体
        current_font = self.text_area.cget("font")
        font_family = current_font.split()[0] if ' ' in current_font else current_font
        font_size = current_font.split()[1] if len(current_font.split()) > 1 else "12"
        
        # 检查是否已经有斜体
        tags = self.text_area.tag_names(tk.SEL_FIRST)
        is_italic = any('italic' in self.text_area.tag_cget(tag, 'font') for tag in tags if self.text_area.tag_cget(tag, 'font'))
        
        if is_italic:
            # 取消斜体
            self.text_area.tag_configure(
                tag_name,
                font=(font_family, int(font_size))
            )
            status_msg = "已取消选中文本的斜体"
        else:
            # 应用斜体
            self.text_area.tag_configure(
                tag_name,
                font=(font_family, int(font_size), "italic")
            )
            status_msg = "已为选中文本应用斜体"
        
        # 将tag应用到选中的文本
        self.text_area.tag_add(tag_name, tk.SEL_FIRST, tk.SEL_LAST)
        self.update_status(status_msg)

    def toggle_underline(self):
        """切换下划线（只对选中文本生效）"""
        if not self.text_area.tag_ranges(tk.SEL):
            messagebox.showinfo("提示", "请先选择要设置下划线的文本")
            return
            
        # 为选中的文本创建新的tag
        tag_name = f"underline_{self.tag_counter}"
        self.tag_counter += 1
        
        # 获取当前字体
        current_font = self.text_area.cget("font")
        font_family = current_font.split()[0] if ' ' in current_font else current_font
        font_size = current_font.split()[1] if len(current_font.split()) > 1 else "12"
        
        # 检查是否已经有下划线
        tags = self.text_area.tag_names(tk.SEL_FIRST)
        is_underline = any(self.text_area.tag_cget(tag, 'underline') == '1' for tag in tags)
        
        if is_underline:
            # 取消下划线
            self.text_area.tag_configure(
                tag_name,
                font=(font_family, int(font_size)),
                underline=False
            )
            status_msg = "已取消选中文本的下划线"
        else:
            # 应用下划线
            self.text_area.tag_configure(
                tag_name,
                font=(font_family, int(font_size)),
                underline=True
            )
            status_msg = "已为选中文本应用下划线"
        
        # 将tag应用到选中的文本
        self.text_area.tag_add(tag_name, tk.SEL_FIRST, tk.SEL_LAST)
        self.update_status(status_msg)

    def toggle_strikethrough(self):
        """切换删除线（只对选中文本生效）"""
        if not self.text_area.tag_ranges(tk.SEL):
            messagebox.showinfo("提示", "请先选择要设置删除线的文本")
            return
            
        # 为选中的文本创建新的tag
        tag_name = f"strikethrough_{self.tag_counter}"
        self.tag_counter += 1
        
        # 获取当前字体
        current_font = self.text_area.cget("font")
        font_family = current_font.split()[0] if ' ' in current_font else current_font
        font_size = current_font.split()[1] if len(current_font.split()) > 1 else "12"
        
        # 检查是否已经有删除线
        tags = self.text_area.tag_names(tk.SEL_FIRST)
        is_strikethrough = any(self.text_area.tag_cget(tag, 'overstrike') == '1' for tag in tags)
        
        if is_strikethrough:
            # 取消删除线
            self.text_area.tag_configure(
                tag_name,
                font=(font_family, int(font_size)),
                overstrike=False
            )
            status_msg = "已取消选中文本的删除线"
        else:
            # 应用删除线
            self.text_area.tag_configure(
                tag_name,
                font=(font_family, int(font_size)),
                overstrike=True
            )
            status_msg = "已为选中文本应用删除线"
        
        # 将tag应用到选中的文本
        self.text_area.tag_add(tag_name, tk.SEL_FIRST, tk.SEL_LAST)
        self.update_status(status_msg)


if __name__ == "__main__":
    root = tk.Tk()
    app = EnhancedNotepad(root)
    root.mainloop()